// 生成基类
const {upperCaseFirstLatter} = require("./common");

function genBaseClass() {
    return `export abstract class JsonBase<T> {
    protected _data: T[]
    // 根据 key 获取数据
    protected _dataByKey: { [key: string]: { [key: string]: T } }

    constructor(data: T[]) {
        this._data = data || []
        this._dataByKey = {}
        // 防止数据更改
        this.forEach(row => {
            Object.freeze(row)
            for (const key in row) {
                // 冻结数组等
                Object.freeze(row[key])
            }
            return true
        })
        this.afterInit()
    }

    // 获取第一行
    getFirstRow(): T | null {
        if (this._data.length > 0) {
            return this._data[0]
        }
        return null
    }

    forEach(cb: (row: T) => boolean) {
        let isOk = false
        for (const d of this._data) {
            isOk = cb(d)
            if (!isOk) {
                // 退出遍历
                break
            }
        }
    }

    // 异步 forEach
    async forEachAsync(cb: (row: T) => Promise<boolean>) {
        let isOk = false
        for (const d of this._data) {
            isOk = await cb(d)
            if (!isOk) {
                // 退出遍历
                break
            }
        }
    }

    // 大小
    get count(): number {
        return this._data.length
    }

    get data() {
        return this._data
    }

    // 设置 key map
    protected _setConfByKeys(keys: string[]) {
        const id = keys.join('-')
        this._dataByKey[id] = {}
        this._data.forEach(row => {
            const list: any[] = []
            keys.forEach(key => {
                if (Object.hasOwnProperty.call(row, key)) {
                    list.push((row as any)[key])
                } else {
                    console.error(\`invalid keys \${JSON.stringify(keys)} for file \${__filename}\`)
                }
            })
            const idValue = list.join('-')
            this._dataByKey[id][idValue] = row
        })
    }

    // 根据 key 获取 value
    protected _getConfByKey(keys: string[], values: any[]) {
        const id = keys.join('-')
        if (!this._dataByKey[id]) {
            return null
        }
        const idValue = values.join('-')
        return this._dataByKey[id][idValue]
    }

    abstract afterInit(): void
}`
}

function genServerClass(tableName, jsonDir) {
    return `import {JsonBase} from './jsonBase'
import {IJson${upperCaseFirstLatter(tableName)}} from '../jsonTable/${tableName}'
import * as ${tableName} from '${jsonDir}/${tableName}.json'

export class Json${upperCaseFirstLatter(tableName)} extends JsonBase<IJson${upperCaseFirstLatter(tableName)}> {

    constructor() {
        // @ts-ignore 处理编译错误
        super(${tableName}.default)
    }

    afterInit(): void {
    }
}
`
}

function genClassMap(classMap) {
    const keys = Object.keys(classMap).sort()
    let types = 'export const gameConfigs: IJsonTable = {\n'
    let importText = ''
    let interfaceTypes = 'export interface IJsonTable {\n'
    for (const key of keys) {
        interfaceTypes += `    ${key}: Json${upperCaseFirstLatter(key)}\n`
        types += `    ${key}: new Json${upperCaseFirstLatter(key)}(),\n`
        importText += `import {Json${upperCaseFirstLatter(key)}} from './${key}'\n`
    }
    interfaceTypes += '}'
    types += '}'
    return importText + '\n' + interfaceTypes + '\n\n' + types
}

function genClientBaseClass() {
    return `export abstract class JsonBase<T> {
    protected _data: T[]
    // 根据 key 获取数据
    protected _dataByKey: { [key: string]: { [key: string]: T } }
    
    init(data: T[]) {
        this._data = data || []
        // 防止数据更改
        this.forEach(row => {
            Object.freeze(row)
            for (const key in row) {
                // 冻结数组等
                Object.freeze(row[key])
            }
            return true
        })
        this.afterInit()
    }
    
    constructor() {
        this._data = []
        this._dataByKey = {}
        // this.afterInit()
    }

    // 获取第一行
    getFirstRow(): T | null {
        if (this._data.length > 0) {
            return this._data[0]
        }
        return null
    }

    forEach(cb: (row: T) => boolean) {
        let isOk = false
        for (const d of this._data) {
            isOk = cb(d)
            if (!isOk) {
                // 退出遍历
                break
            }
        }
    }

    // 异步 forEach
    async forEachAsync(cb: (row: T) => Promise<boolean>) {
        let isOk = false
        for (const d of this._data) {
            isOk = await cb(d)
            if (!isOk) {
                // 退出遍历
                break
            }
        }
    }

    // 大小
    get count(): number {
        return this._data.length
    }

    get data() {
        return this._data
    }

    // 设置 key map
    protected _setConfByKeys(keys: string[]) {
        const id = keys.join('-')
        this._dataByKey[id] = {}
        this._data.forEach(row => {
            const list: any[] = []
            keys.forEach(key => {
                if (Object.hasOwnProperty.call(row, key)) {
                    list.push((row as any)[key])
                } else {
                    console.error(\`invalid keys \${JSON.stringify(keys)} for file \${JSON.stringify(this._data)}\`)
                }
            })
            const idValue = list.join('-')
            this._dataByKey[id][idValue] = row
        })
    }

    // 根据 key 获取 value
    protected _getConfByKey(keys: string[], values: any[]) {
        const id = keys.join('-')
        if (!this._dataByKey[id]) {
            return null
        }
        const idValue = values.join('-')
        return this._dataByKey[id][idValue]
    }

    abstract afterInit(): void
}`
}

// 客户端用
function genClientClass(tableName) {
    return `import {JsonBase} from './jsonBase'
import {IJson${upperCaseFirstLatter(tableName)}} from '../jsonTable/${tableName}Tbl'

export class Json${upperCaseFirstLatter(tableName)} extends JsonBase<IJson${upperCaseFirstLatter(tableName)}> {

    afterInit(): void {
    }
}
`
}

function genClientClassMap(classMap) {
    const keys = Object.keys(classMap).sort()
    let importText = ''
    let interfaceTypes = 'export class GameJsonConfig {\n'
    let constructor = '    constructor() {\n'
    for (const key of keys) {
        interfaceTypes += `    ${key}: Json${upperCaseFirstLatter(key)}\n`
        importText += `import {Json${upperCaseFirstLatter(key)}} from './${key}Model'\n`
        constructor += `        this.${key} = new Json${upperCaseFirstLatter(key)}()\n`
    }
    constructor += `    }
}\n`
    return importText + '\n' + interfaceTypes + '\n\n' + constructor
}


// TODO 生成道具枚举
function genItemKind(data) {

}

module.exports = {
    genBaseClass,
    genServerClass,
    genClassMap,
    genClientBaseClass,
    genClientClassMap,
    genClientClass,
}
